// --------------------------------------------------------------------------------------------------------------------
// <copyright file="AsynchronousTest.cs" company="JDML Consulting Ltd.">
//   Copyright 2011 Photon Project - http://photon.codeplex.com
// </copyright>
// <summary>
//   Defines the AsynchronousTest type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Photon.Testing.Threading
{
    using System;
    using System.Threading;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class AsynchronousTest
    {
        #region Fields

        private IDisposable _asynchronousTestContext;
        private TestContext _testContextInstance;

        #endregion

        public readonly TextLog Log = new TextLog();

        public int DefaultTimeout = 2000;

        public static string DispatcherThreadName
        {
            get
            {
                return "TestDispatcherThread";
            }
        }

        public void EnqueueAction(Action action)
        {
            VerifyContext().Enqueue(new ActionTestActivity(action));
        }

        public void EnqueueWait(Func<bool> condition)
        {
            EnqueueWait(condition, DefaultTimeout);
        }

        public void EnqueueWait(Func<bool> condition, int timeout)
        {
            EnqueueWait(condition, timeout, string.Empty);
        }

        public void EnqueueWait(Func<bool> condition, int timeout, string timeoutMessage)
        {
            VerifyContext().Enqueue(
               new WaitTestActivity(condition, timeout, timeoutMessage));
        }

        public void EnqueueCompleted()
        {
            VerifyContext().Enqueue(CompletedTestActivity.Instance);
        }

        protected static AsynchronousTestContext VerifyContext()
        {
            if (AsynchronousTestContext.Current == null)
            {
                throw new InvalidOperationException("TestMethod must be marked with [AsynchronousTest] attribute.");
            }
            return AsynchronousTestContext.Current;
        }

        public TestContext TestContext
        {
            get
            {
                return _testContextInstance;
            }
            set
            {
                _testContextInstance = value;
            }
        }

        private string EnsureTestName()
        {
            if (_testContextInstance == null)
            {
                throw new InvalidOperationException(
                    "TestContext must be set for asynchronous tests, please ensure your test class does not re-define the TestContext property.");
            }

            return _testContextInstance.TestName;
        }

        [TestInitialize]
        public void AsynchronousTestInitialize()
        {
            if (AsynchronousTestAttribute.IsDefined(GetType().GetMethod(EnsureTestName(), new Type[0])))
            {
                _asynchronousTestContext = AsynchronousTestContext.Create();
            }

            TestThreadInfo.TestThreadId = Thread.CurrentThread.ManagedThreadId;
            Log.Clear();
        }

        [TestCleanup]
        public void AsynchronousTestCleanup()
        {
            if (_asynchronousTestContext != null)
            {
                try
                {
                    _asynchronousTestContext.Dispose();
                }
                finally
                {
                    TestThreadInfo.TestThreadId = null;

                    _asynchronousTestContext = null;
                }
            }
        }
    }
}